

#ifndef __ZXOBJREF_H_
#define __ZXOBJREF_H_

#include "zdbobjptr.h"
#pragma pack (push, 8)

#pragma warning (disable : 4786)

class UcAxObjectRef
{
public:
    UcAxObjectRef();
    UcAxObjectRef(UcDbObjectId objId);
    UcAxObjectRef(UcDbObject *&  pObj); 
    ~UcAxObjectRef();
    
    Ucad::ErrorStatus acquire(UcDbObjectId objId);
    Ucad::ErrorStatus acquire(UcDbObject *& pObj);

    Ucad::ErrorStatus release(UcDbObjectId& objId, UcDbObject *& pObj);
    
    bool isNull();
    UcDbObjectId objectId();

private:
    
    UcAxObjectRef(UcAxObjectRef & ref);
    UcAxObjectRef& operator=(UcAxObjectRef & ref);

    void internalRelease();
    
    UcDbObjectId m_objId;
    UcDbObject *   m_pObj;
};

inline
UcAxObjectRef::UcAxObjectRef()
    : m_objId(NULL),
      m_pObj(NULL)
{
}

inline
UcAxObjectRef::UcAxObjectRef(UcDbObjectId objId)
    : m_objId(NULL),
      m_pObj(NULL)
{   
    acquire(objId);
}

inline
UcAxObjectRef::UcAxObjectRef(UcDbObject *& pObj)
    : m_objId(NULL),
      m_pObj(NULL)
{
    acquire(pObj);
}

inline
UcAxObjectRef::~UcAxObjectRef()
{
    internalRelease();
}
    
inline Ucad::ErrorStatus
UcAxObjectRef::acquire(UcDbObjectId objId)
{
    if (objId.isNull())
        return Ucad::eNullObjectId;
    
    internalRelease();
    
    m_objId = objId;
    return Ucad::eOk;
}

inline Ucad::ErrorStatus
UcAxObjectRef::acquire(UcDbObject *& pObj)
{
    if (NULL == pObj)
        return Ucad::eNullObjectPointer;
    
    if (!pObj->objectId().isNull())
        return acquire(pObj->objectId());

    internalRelease();

    m_pObj = pObj;
    pObj = NULL;
    
    return Ucad::eOk;
}
    
inline Ucad::ErrorStatus
UcAxObjectRef::release(UcDbObjectId& objId, UcDbObject *& pObj)
{
    if (isNull())
        return Ucad::eNullObjectPointer;

    pObj = m_pObj;
    objId = m_objId;

    m_pObj = NULL;
    m_objId.setNull();
    
    return Ucad::eOk;
}

inline void
UcAxObjectRef::internalRelease()
{
    if (NULL != m_pObj) 
    {
        if (m_pObj->objectId().isNull())
            delete m_pObj;
    
        else
        {
        }
        m_pObj = NULL;
    }
    m_objId.setNull();
}

inline bool
UcAxObjectRef::isNull()
{
    return (NULL == m_pObj && m_objId.isNull());
}

inline UcDbObjectId
UcAxObjectRef::objectId()
{
    return m_objId;
}

template<class T_OBJECT>
class UcAxObjectRefPtr : public UcDbObjectPointer<T_OBJECT>
{
public:
    UcAxObjectRefPtr();
    UcAxObjectRefPtr(UcAxObjectRef* const pRef,
                     UcDb::OpenMode mode,
                     bool           openErased = false);
    ~UcAxObjectRefPtr();

private:
    
    UcAxObjectRefPtr(UcAxObjectRefPtr & pObj);
    UcAxObjectRefPtr& operator=(UcAxObjectRefPtr & pObj);

    UcAxObjectRef* const m_pRef;
};

template<class T_OBJECT> inline
UcAxObjectRefPtr<T_OBJECT>::UcAxObjectRefPtr()
    : UcDbObjectPointer<T_OBJECT>(),
      m_pRef(NULL)
{}

template<class T_OBJECT> inline 
UcAxObjectRefPtr<T_OBJECT>::UcAxObjectRefPtr(UcAxObjectRef* const pRef, UcDb::OpenMode mode, bool openErased)
    : m_pRef(pRef)
{
    
    if (NULL == pRef)
    {
        this->m_status = Ucad::eNullObjectPointer;
        return;
    }

    UcDbObjectId objId = pRef->objectId();

    if (!objId.isNull())
        this->m_status = ucdbOpenObject(this->m_ptr, objId, mode, openErased);
    else
    {
        UcDbObject* pTmp = NULL;
        m_pRef->release(objId, pTmp);

        T_OBJECT* pTyped= T_OBJECT::cast(pTmp);
        if (NULL == pTyped) {
            this->m_ptr = NULL;
            m_pRef->acquire(pTmp);
            this->m_status = Ucad::eNotThatKindOfClass;
        }
        else
            this->acquire(pTyped);
    }
}
    
template<class T_OBJECT> inline
UcAxObjectRefPtr<T_OBJECT>::~UcAxObjectRefPtr()
{
    if (NULL != this->m_ptr && this->m_ptr->objectId().isNull()) {
        T_OBJECT* pTmp;
        this->release(pTmp);
        m_pRef->acquire(reinterpret_cast<UcDbObject*&>(pTmp));
    }
}

typedef UcAxObjectRefPtr<UcDbObject> UcDbObjectRefPtr;
typedef UcAxObjectRefPtr<UcDbEntity> UcDbEntityRefPtr;

#pragma pack (pop)
#endif
